-- UIMsgReminder
-- Created by zouyb Oct/25/2015
-- 消息提醒界面
-- (注意：本窗口将会以子窗口的形式，添加到UIMainMap或UIDungenMain上面)

UIMsgReminder = class("UIMsgReminder", function()
    return cc.Layer:create();
end);

function UIMsgReminder.create(inMainMap)
    return UIMsgReminder.new(inMainMap);
end

local limitGiftAlert = {};

function UIMsgReminder:ctor(inMainMap)
    -- 初始化
    self:setName("UIMsgReminder");
    local node = cc.CSLoader:createNode("layout/reminder/MsgReminder.csb");
    self:addChild(node);
    self.node = node;

    -- 大地图上提示
    self.inMainMap = inMainMap;

    limitGiftAlert = {
        ["fail"] = getLocStr("take_time_gift_fail"),
        ["over_time"] = getLocStr("take_time_gift_over_time"),
        ["take_already"] = getLocStr("take_time_gift_already"),
    };

    -- 适配
    self:resize();

    -- 记录初始位置
    local itemParent = findChildByName(self.node, "TOP/reminder_parent");
    self.initPosY = itemParent:getPositionY();

    self:setLocalZOrder(UIMgr.TOP_MENU_ZORDER + 2);

    -- 注册事件处理回调函数
    self:registerEventCallback();

    -- 初始化
    self:update();
end

-- 适配
function UIMsgReminder:resize()
    local node = self.node;

    -- TOP置于顶部中心并缩放至合适大小
    AlignM.alignToTopCenter(node, "TOP");
end

-- 注册事件处理回调函数
function UIMsgReminder:registerEventCallback()
    local name = "UIMsgReminder" .. iif(self.inMainMap, "0", "1");

    -- 注册复活的回调
    EventMgr.removeAll(name);
    EventMgr.register(name, event.NEW_REMINDER_COMING, function(curType)
        -- 重新初始化
        self:update(curType);
    end);

    -- 偏移时间到达事件
    EventMgr.register(name, event.TIME_OFFSET_ARRIVER, function()
        -- 重新初始化
        if self.inMainMap then
            self:update();
        end
    end);

    -- 领取限时礼包事件
    EventMgr.register(name, event.TAKE_TIME_GIFT_RESULT, function(args)
        -- 重新初始化
        if self.inMainMap then
            self:update();
            if not UIMgr.getCurrentScene():getFormByName("UIMarketMain") then
                self:takeBonusTip(args);
            end
        end
    end);

    -- 限时礼包数据刷新
    EventMgr.register(name, event.USER_INFO_UPDATED, function(args)
        if args == "limit_time_gift" then
            if self.inMainMap then
                -- 重新初始化
                self:update();
            end
        end
    end);

    -- 关注商城充值开关变化的事件
    EventMgr.register(name, event.RECHARGE_ENABLED, function(enabled)
        if self.inMainMap then
            self:update();
        end
    end);

    -- 关注通关事件
    EventMgr.register(name, event.DUNGEON_PASS, function(para)
        local dungeonId = para["dungeonId"];
        if self.inMainMap and dungeonId == MarketM.getOpenDungeon() then
            self:update();
        end
    end);

    -- 界面析构后，需要清理下
    self:registerScriptHandler(function(ev)
        if ev == "exit" then
            -- 移除所有事件回调
            EventMgr.removeAll(name);
        end
    end);
end

-- 领奖提示
function UIMsgReminder:takeBonusTip(args)
    UIMgr.getCurrentScene():removeFormByName("UISuperiorBonusTip");
    local result = args.result;
    if type(result) == "table" then
        -- 通用奖励提示框
        local title = getLocStr("time_limit_gift");
        -- 转换奖励数据
        local bonusList = {};
        for _, bonus in pairs(result) do
            table.insert(bonusList, bonus);
        end

        local function okFunc()
            checkFirstChargeBonus();
        end

        showBonusNotifyForm(title, bonusList, okFunc, nil, nil, nil, nil, nil, {["noSortBonus"] = true});
    elseif type(result) == "string" then
        -- 弹字提示
        if limitGiftAlert[result] then
            alert(limitGiftAlert[result]);
        else
            alert(limitGiftAlert["fail"]);
        end
    end
end

-- 更新消息提醒
function UIMsgReminder:update(curType)
    local itemParent = findChildByName(self.node, "TOP/reminder_parent");
    local reminderList = MsgReminderM.getReminderList();
    self.giftItem = nil;

    -- 迷宫外和迷宫内的高度位置显示略有不同
    if self.inMainMap then
        itemParent:setPositionY(self.initPosY - 60);

        -- 检查限时礼包
        local limitGiftInfo = self:checkLimitMsgReminder();
        if limitGiftInfo then
            if not reminderList[MsgReminderM.MSG_REMINDER_LIMIT_GIFT] then
                reminderList[MsgReminderM.MSG_REMINDER_LIMIT_GIFT] = {1};
            end
        end
    end

    -- 初始位置
    self.initPosX = 0;

    -- 遍历所有事件
    local needNotify = false;
    for reminderType, list in pairs(reminderList) do
        repeat
            if self.inMainMap then
                if (reminderType ~= MsgReminderM.MSG_REMINDER_LIMIT_GIFT) and
                    (reminderType ~= MsgReminderM.MSG_REMINDER_TYPE_ACHIEVEMENT) and
                        (reminderType ~= MsgReminderM.MSG_REMINDER_TYPE_PAUSE) then
                    -- 大地图上只显示成就/限时/暂离
                    break;
                end
            else
                if reminderType == MsgReminderM.MSG_REMINDER_LIMIT_GIFT
                    or reminderType == MsgReminderM.MSG_REMINDER_TYPE_PAUSE then
                    -- 迷宫内不显示限时和暂离
                    MsgReminderM.removeReminder(MsgReminderM.MSG_REMINDER_TYPE_PAUSE, 1);
                    break;
                elseif reminderType == MsgReminderM.MSG_REMINDER_TYPE_MAIL
                    and DungeonM.hidePauseDungeon() then
                    -- 不能暂离的夹层不显示MAIL类的提示
                    break;
                end
            end

            self:initItem(reminderType, list, curType);

            local count = MsgReminderM.getCountByType(reminderType);
            if count > 0 then
                needNotify = true;
            end
        until true;
    end

    if needNotify and not self.inMainMap then
        -- 抛出事件用来告诉迷宫内的能量条变透明
        EventMgr.fire(event.MSG_REMINDER_APPEAR);
    end
end

-- 限时礼包提示显示
function UIMsgReminder:checkLimitMsgReminder()
    if not self.inMainMap then
        return;
    end

    if not MarketM.isRechargeOpen() then
        -- 没开充值，不显示
        return;
    end

    if not GiftM.canShowLimitTimeGift() then
        -- 没有数据或者已经领取过了
        return;
    end

    return true;
end

-- 限时礼包提示
function UIMsgReminder:openLimitGiftInfo()
    require "game/ui/form/market/UISuperiorBonusTip";
    -- 限时礼包
    local info = table.deepcopy(GiftM.getLimitTimeGiftInfo());
    local title = getLocStr("time_limit_gift");
    local bonusList = info.gift_info["bonus_list"];
    local goodsInfo = MarketM.getGoodsInfo(info.gift_info["good_id"]);
    local goodName = goodsInfo["name"];
    local goodsId = goodsInfo["id"];
    local msg = string.format(getLocStr("time_limit_gift_desc"), goodName);
    local sku = MarketM.querySku(goodsId);
    local price;
    if type(sku) ~= 'string' then
        price = string.format("$%.2f", table.values(goodsInfo["price"])[1]);
    else
        price = MarketM.getPriceBySku(sku);
    end

    local value = FormulaM.invoke("CALC_MARKET_BONUS_VALUE", bonusList, info.gift_info["good_id"]);

    if not GiftM.ifAchieveTimeLimitGift() then
        -- 没完成
        local okText, originalText = MarketM.transformPriceText(price, value);

        local extraPara = {["timeLimitGift"] = true, ["is_taken"] = false, ["original_price"] = originalText, ["gift_id"] = info.gift_info["gift_id"]};
        local function okFunc()
            -- 播放界面音效
            AudioM.playFx("market_buy_btn");
            -- 去除自身界面
            UIMgr.getCurrentScene():removeFormByName("UISuperiorBonusTip");

            if not MarketM.isRechargeOpen() then
                -- 充值功能暂未开放
                alert(getLocStr("disable_function"));
                return;
            end

            -- 直接显示系统提示
            self:systemBuyNotify(info.gift_info["good_id"], 2);
        end
        local uiForm = UISuperiorBonusTip.create(title, msg, value,
            bonusList, okText, okFunc, extraPara);
        UIMgr.getCurrentScene():addForm(uiForm);
        AudioM.playFx("market_dlc");
    elseif not GiftM.takeTimeLimitBonusAlready() then
        -- 发送领取请求
        local function okFunc()
            Operation.cmd_take_time_gift_bonus();
        end

        msg = string.format(getLocStr("time_limit_gift_desc2"), goodName);
        local okText = getLocStr("btn_text_take_gift");
        local extraPara = {["timeLimitGift"] = true, ["is_taken"] = true, ["gift_id"] = info.gift_info["gift_id"]};
        local uiForm = UISuperiorBonusTip.create(title, msg, value,
            bonusList, okText, okFunc, extraPara);
        UIMgr.getCurrentScene():addForm(uiForm);
        AudioM.playFx("market_dlc");
    end
end

-- 系统充值界面
function UIMsgReminder:systemBuyNotify(goodsId, priceType)
    -- 获取商品信息
    local goodsInfo = MarketM.getGoodsInfo(goodsId);

    -- 真钱购买
    if priceType ~= 1 then
        -- 如果在手机上，通过sdk购买（pt购买不限手机平台）
        if isAndroidPlatform() or isIosPlatform() or MarketM.isBuyGemByPt() then
            if self.buying == true then
                return;
            end

            -- 可选择支付宝或微信
            if MarketM.isInlandPayWay() then
                showInlandPayWay(goodsId);
            else
                MarketM.buyByRmb(goodsId);
            end

            -- 标记正在购买，避免点太快导致崩溃
            self.buying = true;
            performWithDelay(self, function() self.buying = false; end, 0.5);
        else
            -- 暂未开放
            alert(getLocStr("disable_function"));
        end
    end
end

-- 初始化某类提醒
function UIMsgReminder:initItem(reminderType, list, curType)
    local firstAppear = false;

    if self.items == nil then
        self.items = {};
    end

    local count;

    -- 限时礼包
    if reminderType == MsgReminderM.MSG_REMINDER_LIMIT_GIFT then
        if self:checkLimitMsgReminder() then
            count = 1;
        else
            count = 0;
        end
    else
        count = MsgReminderM.getCountByType(reminderType);
    end

    if count == 0 then
        -- 渐隐消失
        local item = self.items[reminderType];
        if item then
            local fadeOut = cc.FadeOut:create(0.5);
            local callFunc = cc.CallFunc:create(function()
                item:removeFromParent();
                EventMgr.fire(event.MSG_REMINDER_DISAPPEAR);
            end);

            item:runAction(cc.Sequence:create(fadeOut, callFunc));
        end

        self.items[reminderType] = nil;
        return;
    end

    -- 之前没有提醒，本次有提醒，需要显示动画效果
    if not self.items[reminderType] then
        firstAppear = true;
        self.items[reminderType] = cc.CSLoader:createNode("layout/reminder/ReminderItem.csb");
        local itemParent = findChildByName(self.node, "TOP/reminder_parent");
        itemParent:addChild(self.items[reminderType]);
    end

    local item = self.items[reminderType];

    -- 个数
    local mulLabel = findChildByName(item, "bg/mul");
    local numLabel = findChildByName(item, "bg/num");

    if firstAppear then
        TextStyleM.setTextStyle(mulLabel, TextStyleM.TEXT_SIZE_TINY, TextStyleM.TEXT_COLOR_BROWN_YELLOW, true);
        mulLabel:setString("x");
        TextStyleM.setTextStyle(numLabel, TextStyleM.TEXT_SIZE_MINI, TextStyleM.TEXT_COLOR_BROWN_YELLOW, true);
    end

    numLabel:setString(tostring(count));

    if count <= 1 then
        mulLabel:setVisible(false);
        numLabel:setVisible(false);
    else
        mulLabel:setVisible(true);
        numLabel:setVisible(true);
    end

    -- 图标显示
    local iconPath = getReminderIcon(reminderType);
    local bg = findChildByName(item, "bg");
    bg:setCascadeOpacityEnabled(true);
    local icon = findChildByName(item, "bg/icon");
    icon:loadTexture(iconPath);
    if MsgReminderM.MSG_REMINDER_TYPE_PAUSE == reminderType then
        local pauseIcon = findChildByName(item, "icon");
        pauseIcon:loadTexture(iconPath);
        pauseIcon:setScale(0.75);
        pauseIcon:setVisible(true);
        local size = pauseIcon:getContentSize();
        playBubbleAnima2(pauseIcon, false, 0.75, 0.6, true);
        local effetNode = findChildByName(item, "icon/effect_node");
        -- effetNode:setPosition(size.width/2, size.height/2)

        -- 传送门光效
        effetNode:removeAllChildren();
        playEffect(effetNode, 1293, 0, 0, nil);
        bg:setOpacity(0);
        local pausingLabel = findChildByName(item, "pausing_label");
        local kerning = -4;
        if not isFullWidthLang() then
            kerning = -2;
        end
        TextStyleM.setTextStyle(pausingLabel, TextStyleM.TEXT_SIZE_TINY, TextStyleM.TEXT_COLOR_WHITE, true, kerning, nil, nil, nil, nil, true);
        pausingLabel:setString(getLocStr("dungeon_pausing"));
        pausingLabel:setVisible(true);
    end

    -- 点击处理
    local function onClick(sender, eventType)
        if  eventType == ccui.TouchEventType.began then
            item:setScale(0.9);
        elseif eventType == ccui.TouchEventType.canceled then
            item:setScale(1);
        elseif eventType == ccui.TouchEventType.ended then
            item:setScale(1);

            if reminderType == MsgReminderM.MSG_REMINDER_LIMIT_GIFT then
                -- 打开礼包界面
                self:openLimitGiftInfo();
                return;
            end

            for _, args in pairs(list) do
                local id = args["id"];

                local function onOK()
                    self:update();

                    if reminderType == MsgReminderM.MSG_REMINDER_TYPE_ACHIEVEMENT
                        and not self.inMainMap then
                        -- 地牢内点击成就，还需要更新主地图
                        if UIMgr.getCurrentScene().mainMap then
                            UIMgr.getCurrentScene().mainMap:updateMsgReminderUI();
                        end
                    end

                    count = MsgReminderM.getCountByType(reminderType);
                    if count >= 1 then
                        onClick(sender, eventType);
                    end
                end

                local backText = "btn_text_back";
                count = MsgReminderM.getCountByType(reminderType);
                if count > 1 then
                    backText = "btn_text_continue";
                end

                if reminderType == MsgReminderM.MSG_REMINDER_TYPE_MONSTER then
                    -- 显示怪物信息
                    args["backText"] = backText;
                    args["backFunc"] = onOK;
                    EventMgr.fire(event.MONSTER_INFO_AUTO_APPEAR, args);
                    MsgReminderM.removeReminder(MsgReminderM.MSG_REMINDER_TYPE_MONSTER, id);

                    local name = "UIMsgReminder" .. iif(self.inMainMap, "0", "1");
                    EventMgr.remove(name, event.FOCUS_CHANGED)
                    EventMgr.register(name, event.FOCUS_CHANGED, function(para)
                        if para["lose"] == "UIMonsterInfo" or para["lose"] == "UIBossMonsterInfo" then
                            self:update();
                        end
                    end);

                elseif reminderType == MsgReminderM.MSG_REMINDER_TYPE_ACHIEVEMENT then
                    -- 显示成就信息
                    local name = GameAchievementM.query(id, "name");
                    local parentId = GameAchievementM.query(id, "parent_id");
                    if parentId == 0 then
                        parentId = id;
                    end

                    local totalScore = GameAchievementM.getTotalScore(parentId);
                    local msg = string.format(getLocStr("achievement_reached"), name, totalScore);

                    local function showTip()
                        confirm2(CONFIRM_TYPE_OK, getLocStr("achievement_completed"), msg, onOK, nil, nil, nil, { ["backFunc"] = onOK, ["backText"] = backText});
                    end

                    showTip();

                    MsgReminderM.removeReminder(MsgReminderM.MSG_REMINDER_TYPE_ACHIEVEMENT, id);
                elseif reminderType == MsgReminderM.MSG_REMINDER_TYPE_EVENT then
                    -- 显示迷宫事件
                    local function showTip()
                        local desc = AchievementM.queryDesc(id);
                        local dp   = AchievementM.query(id, "dp");
                        desc = string.format(getLocStr("dungeon_event_completed_desc"), desc, dp);
                        confirm2(CONFIRM_TYPE_OK, getLocStr("dungeon_event_completed"), desc, onOK, nil, nil, nil, { ["backFunc"] = onOK, ["backText"] = backText});
                    end

                    showTip();

                    MsgReminderM.removeReminder(MsgReminderM.MSG_REMINDER_TYPE_EVENT, id);
                elseif reminderType == MsgReminderM.MSG_REMINDER_TYPE_TASK then
                    -- 显示迷宫任务达成
                    local function showTip()
                        local desc = DungeonTaskM.query(id, "complete_tip");
                        confirm2(CONFIRM_TYPE_OK, getLocStr("task_completed"), desc, onOK, nil, nil, nil, { ["backFunc"] = onOK, ["backText"] = backText});
                    end

                    showTip();

                    MsgReminderM.removeReminder(MsgReminderM.MSG_REMINDER_TYPE_TASK, id);
                elseif reminderType == MsgReminderM.MSG_REMINDER_TYPE_PAUSE then
                    -- 进入地牢
                    MsgReminderM.removeReminder(MsgReminderM.MSG_REMINDER_TYPE_PAUSE, 1);
                    if DungeonM.isInDungeon() or DungeonM.isPause() then
                        -- 显示通信中界面
                        -- showCommunicatingForm();

                        -- 暂离状态，直接进入
                        local id = ME.user.dbase:query("current_dungeon");
                        DungeonServiceM.startEnterService(id);
                    end
                elseif reminderType == MsgReminderM.MSG_REMINDER_TYPE_MAIL then
                    -- 邮件提示
                    self:onReceiveMail();
                end

                break;
            end
        end
    end
    bg:addTouchEventListener(onClick);

    -- 初始化位置
    item:setPositionX(self.initPosX);
    local oldPos = cc.p(item:getPosition());

    -- 计算下一类提醒的坐标
    self.initPosX = self.initPosX - 100;

    -- 动画效果
    if MsgReminderM.MSG_REMINDER_TYPE_PAUSE == reminderType then
        self:showEffect2(item, firstAppear, oldPos, curType, reminderType);
    else
        self:showEffect(item, firstAppear, oldPos, curType, reminderType);
    end

    -- 时间回调
    self:redrawTime(item, reminderType);

    -- 检查置灰
    if reminderType == MsgReminderM.MSG_REMINDER_LIMIT_GIFT then
        self.giftItem = item;
        self:checkGray();
    end
end

-- 收到邮件
function UIMsgReminder:onReceiveMail()
    function okFunc()
        -- 暂离
        UIDungeonMgr.pauseDungeon();
        -- 清除无用纹理
        UIMgr.clearUnusedTextures();
        MsgReminderM.removeReminder(MsgReminderM.MSG_REMINDER_TYPE_MAIL, 1);
        -- 打开邮箱界面
        require "game/ui/form/mail/UIMailList";
        local uiForm = UIMailList.create();
        UIMgr.getCurrentScene():addForm(uiForm);

    end

    function cancelFunc()
        -- 关闭提示
        MsgReminderM.removeReminder(MsgReminderM.MSG_REMINDER_TYPE_MAIL, 1);
        self:update();
    end

    local desc = getLocStr("receive_mail_tip");
    confirm2(CONFIRM_TYPE_OK_CANCEL, getLocStr("slime_note"),
        desc, okFunc, cancelFunc, getLocStr("btn_text_to_see"),
        getLocStr("btn_text_see_later"), { ["backFunc"] = cancelFunc, ["cancelColor"] = "blue"});
end

-- 检查置灰
function UIMsgReminder:checkGray(force)
    if not self.giftItem then
        return;
    end

    local blendColor = TextStyleM.TEXT_COLOR_BLEND;
    local normalColor = TextStyleM.TEXT_COLOR_NORMAL;

    local bg = findChildByName(self.giftItem, "bg");
    local icon = findChildByName(self.giftItem, "bg/icon");

    bg:setColor(normalColor);
    icon:setColor(normalColor);
end

-- 时间回调
function UIMsgReminder:redrawTime(item, reminderType)
    local timeLabel = findChildByName(item, "bg/time");
    TextStyleM.setTextStyle(timeLabel, TextStyleM.TEXT_SIZE_TINY, TextStyleM.TEXT_COLOR_WHITE, true, -4);
    if reminderType~= MsgReminderM.MSG_REMINDER_LIMIT_GIFT then
        if reminderType == MsgReminderM.MSG_REMINDER_TYPE_PAUSE then
            timeLabel:setVisible(true);
        else
            timeLabel:setVisible(false);
        end
        return;
    end

    self.tryRefreshTime = 0;

    if item.isTick then
        return;
    end

    local function tick()
        -- 限时礼包倒计时
        local leftTime = GiftM.getLimitGiftLeftTime();
        local timeText;
        local hour = math.floor(leftTime / 3600);
        local minute = math.floor((leftTime - hour * 3600) / 60);
        local second = math.floor(leftTime % 60);
        timeText = string.format(getLocStr("left_time"), hour, minute, second);
        -- 可见的时候才去设置字符串
        if timeLabel:isVisible() then
            timeLabel:setString(timeText);
        end

        if leftTime <= 0 then
            self.tryRefreshTime = self.tryRefreshTime + 1;
            if math.floor(self.tryRefreshTime % 10) == 0 then
                -- 请求更新/10s请求一次
                Operation.cmd_update_time_limit_gift_info();
            end
        end
        performWithDelay(item, tick, 1);
    end
    item.isTick = true;
    tick();
    timeLabel:setVisible(true);
end

-- 动画效果
function UIMsgReminder:showEffect(item, firstAppear, oldPos, curType, reminderType)
    -- 出场动画
    print("firstAppear:" .. tostring(firstAppear));
    if firstAppear then
        -- 节点从右往左飞入，并略微回弹下
        item:setPosition(item:getPositionX() + 200, item:getPositionY());
        local moveDown = cc.EaseIn:create(cc.MoveTo:create(0.15, cc.p(oldPos.x - 30, oldPos.y)), 0.8);
        local callFunc1 = cc.CallFunc:create(function()
            -- 震动效果
            if DungeonM.isInDungeon() and UIDungeonMgr.getCurLevel() then
                playShakeEffect(UIDungeonMgr.getCurLevel(), 0.03, 4, 4);
            else
                playShakeEffect(UIMgr.getCurrentScene().mainMap, 0.03, 1, 1);
            end

            -- 烟尘效果
            local effetNode = findChildByName(item, "effect");
            local _, effect = playEffect(effetNode, 1172, 40, -80);
            effect:setScale(0.88);
        end);
        local moveBack = cc.MoveTo:create(0.05, cc.p(oldPos.x, oldPos.y));
        local callFunc2 = cc.CallFunc:create(function()

            end);

        item:stopAllActions();
        item:runAction(cc.Sequence:create(moveDown, callFunc1, moveBack, callFunc2));

        -- 摆动效果
        self:dangle(item, reminderType);
    else
        if curType ~= nil and reminderType == curType then
            -- 虚化扩散
            local bg = findChildByName(item, "bg");
            local bgCopy = bg:clone();
            bgCopy:setCascadeOpacityEnabled(true);
            bgCopy:setOpacity(150);

            bgCopy:setAnchorPoint(cc.p(0.5, 0.5));
            bgCopy:setPositionY(bgCopy:getPositionY() - 40);

            local scaleUp = cc.ScaleTo:create(0.6, 1.4);
            local fadeOut = cc.FadeOut:create(0.6);
            local callFunc = cc.CallFunc:create(function()
                bgCopy:removeFromParent();

                -- 摆动效果
                self:dangle(item);
            end);
            bgCopy:runAction(cc.Sequence:create(cc.Spawn:create(scaleUp, fadeOut), callFunc));
            item:addChild(bgCopy);

            -- 烟尘效果
            local effetNode = findChildByName(item, "effect");
            local _, effect = playEffect(effetNode, 1172, 40, -80);
            effect:setScale(0.88);
        else
            -- 摆动效果
            self:dangle(item, reminderType);
        end
    end
end

-- 平常的摇晃效果
function UIMsgReminder:dangle(item, reminderType)
    local bg = findChildByName(item, "bg");
    bg:stopAllActions();

    -- 传送之门不摇晃
    if MsgReminderM.MSG_REMINDER_TYPE_PAUSE == reminderType then
        return;
    end

    local function shake()
        local rangeAngle = 5;

        if not UIDungeonMgr.getCurLevel() or not UIDungeonMgr.getCurLevel().isTimeCeasing then
            bg:setRotation(0);
            local rotateLeft = cc.RotateBy:create(0.2, rangeAngle);
            local rotateRight = cc.RotateBy:create(0.4, -rangeAngle * 2);
            local rotateBack = cc.RotateBy:create(0.2, rangeAngle);
            local rotateLeft2 = cc.RotateBy:create(0.1, rangeAngle / 2);
            local rotateRight2 = cc.RotateBy:create(0.2, -rangeAngle);
            local rotateBack2 = cc.RotateBy:create(0.1, rangeAngle / 2);
            bg:runAction(cc.Sequence:create(rotateLeft, rotateRight, rotateBack, rotateLeft2, rotateRight2, rotateBack2));
        end

        performWithDelay(bg, shake, 3);
    end
    performWithDelay(bg, shake, 0.5);
end

-- 动画效果
function UIMsgReminder:showEffect2(item, firstAppear, curType, reminderType)
    -- 出场动画(砸在地板上的效果)
    if firstAppear then
        -- 节点从右往左飞入，并略微回弹下
        local oldScale = item:getScale();
        item:setScale(3 * oldScale);
        local moveDown = cc.EaseIn:create(cc.ScaleTo:create(0.15, oldScale), 0.8);
        local callFunc1 = cc.CallFunc:create(function()
            -- 震动效果
            if DungeonM.isInDungeon() and UIDungeonMgr.getCurLevel() then
                playShakeEffect(UIDungeonMgr.getCurLevel(), 0.03, 4, 4);
            else
                playShakeEffect(UIMgr.getCurrentScene().mainMap, 0.03, 4, 3);
            end

            -- 烟尘效果
            local effetNode = findChildByName(item, "effect");
            local _, effect = playEffect(effetNode, 1172, 40, -80);
            effect:setScale(0.88);
        end);

        item:stopAllActions();
        item:runAction(cc.Sequence:create(moveDown, callFunc1));
    else
        if curType ~= nil and reminderType == curType then
            -- 虚化扩散
            local bg = findChildByName(item, "bg");
            local bgCopy = bg:clone();
            bgCopy:setCascadeOpacityEnabled(true);
            bgCopy:setOpacity(150);

            bgCopy:setAnchorPoint(cc.p(0.5, 0.5));
            bgCopy:setPositionY(bgCopy:getPositionY() - 40);

            local scaleUp = cc.ScaleTo:create(0.6, 1.4);
            local fadeOut = cc.FadeOut:create(0.6);
            local callFunc = cc.CallFunc:create(function()
                bgCopy:removeFromParent();

                -- 摆动效果
                self:dangle(item);
            end);
            bgCopy:runAction(cc.Sequence:create(cc.Spawn:create(scaleUp, fadeOut), callFunc));
            item:addChild(bgCopy);

            -- 烟尘效果
            local effetNode = findChildByName(item, "effect");
            local _, effect = playEffect(effetNode, 1172, 40, -80);
            effect:setScale(0.88);
        else
            -- 摆动效果
            self:dangle(item, reminderType);
        end
    end
end